home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Cappuccino / Source / Printer.cpp < prev    next >
Encoding:
Text File  |  1995-12-11  |  16.8 KB  |  647 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Printer.cpp
  3.  
  4.     Contains:    Implementation of CPrinter class for OpenDoc printing utility
  5.  
  6.     Written by:    Steve Smith, Thomas Weisbach, Jens Alfke
  7.  
  8.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11.  
  12.  
  13. // -- OpenDoc --
  14.  
  15. #ifndef _ALTPOINT_
  16. #include <AltPoint.h>
  17. #endif
  18.  
  19. #ifndef SOM_ODCanvas_xh
  20. #include <Canvas.xh>
  21. #endif
  22.  
  23. #ifndef SOM_ODClipboard_xh
  24. #include <Clipbd.xh>
  25. #endif
  26.  
  27. #ifndef SOM_Module_OpenDoc_Commands_defined
  28. #include <CmdDefs.xh>
  29. #endif
  30.  
  31. #ifndef SOM_ODDispatcher_xh
  32. #include <Disptch.xh>
  33. #endif
  34.  
  35. #ifndef SOM_ODFacet_xh
  36. #include <Facet.xh>
  37. #endif
  38.  
  39. #ifndef SOM_ODFrame_xh
  40. #include <Frame.xh>
  41. #endif
  42.  
  43. #ifndef SOM_ODMenuBar_xh
  44. #include <MenuBar.xh>
  45. #endif
  46.  
  47. #ifndef SOM_ODSession_xh
  48. #include <ODSessn.xh>
  49. #endif
  50.  
  51. #ifndef SOM_ODStorageSystem_xh
  52. #include <ODStor.xh>
  53. #endif
  54.  
  55. #ifndef SOM_ODPart_xh
  56. #include <Part.xh>
  57. #endif
  58.  
  59. #ifndef SOM_ODPlatformTypeList_xh
  60. #include <PfTypLs.xh>
  61. #endif
  62.  
  63. #ifndef SOM_ODShape_xh
  64. #include <Shape.xh>
  65. #endif
  66.  
  67. #ifndef SOM_Module_OpenDoc_StdProps_defined
  68. #include <StdProps.xh>
  69. #endif
  70.  
  71. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  72. #include <StdTypes.xh>
  73. #endif
  74.  
  75. #ifndef SOM_ODStorageUnit_xh
  76. #include <StorageU.xh>
  77. #endif
  78.  
  79. #ifndef SOM_ODTransform_xh
  80. #include <Trnsform.xh>
  81. #endif
  82.  
  83. #ifndef SOM_ODWindowState_xh
  84. #include <WinStat.xh>
  85. #endif
  86.  
  87. // -- OpenDoc Utilities --
  88.  
  89. #ifndef _EXCEPT_
  90. #include <Except.h>
  91. #endif
  92.  
  93. #ifndef _ITEXT_
  94. #include <IText.h>
  95. #endif
  96.  
  97. #ifndef _DLOGUTIL_
  98. #include <DlogUtil.h>
  99. #endif
  100.  
  101. #ifndef _ODDEBUG_
  102. #include <ODDebug.h>
  103. #endif
  104.  
  105. #ifndef _ODNEW_
  106. #include <ODNew.h>
  107. #endif
  108.  
  109. #ifndef _ODUTILS_
  110. #include <ODUtils.h>
  111. #endif
  112.  
  113. #ifndef _STORUTIL_
  114. #include <StorUtil.h>
  115. #endif
  116.  
  117. #ifndef _TEMPOBJ_
  118. #include <TempObj.h>
  119. #endif
  120.  
  121. #ifndef _USERSRCM_
  122. #include <UseRsrcM.h>
  123. #endif
  124.  
  125. // -- MacToolbox --
  126.  
  127. #ifndef __GESTALT__
  128. #include <Gestalt.h>
  129. #endif
  130.  
  131. #ifndef __GXGRAPHICS__
  132. #include <GXGraphics.h>
  133. #endif
  134.  
  135. #ifndef __GXPRINTING__
  136. #include <GXPrinting.h>
  137. #endif
  138.  
  139. #ifndef __PRINTING__
  140. #include <Printing.h>
  141. #endif
  142.  
  143. #ifndef __TEXTUTILS__
  144. #include <TextUtils.h>
  145. #endif
  146.  
  147. #ifndef __TOOLUTILS__
  148. #include <ToolUtils.h>
  149. #endif
  150.  
  151. // -- Printer --
  152. #define _PRINTER_PRIVATE_
  153. #ifndef _PRINTER_
  154. #include "Printer.h"
  155. #endif
  156.  
  157. #pragma segment Printer
  158.  
  159.  
  160. //=================================================================================
  161. // CWithPrintingOpen helper class
  162. //
  163. //    This is a stack-based object that opens printing in its constructor and
  164. //    closes it in its destructor. This provides a simple and exception-safe way
  165. //    to open up printing for the duration of a method or block.
  166. //=================================================================================
  167.  
  168. CWithPrintingOpen::CWithPrintingOpen( CPrinter *printer )
  169.     :fPrinter(kODNULL)
  170. {
  171.     if( ! printer->IsPrintingOpen() ) {
  172.         printer->OpenPrinting();            // Only open it if it wasn't open
  173.         fPrinter = printer;
  174.     }
  175. }
  176.  
  177. CWithPrintingOpen::~CWithPrintingOpen( )
  178. {
  179.     if( fPrinter )
  180.         fPrinter->ClosePrinting();            // Only close if printing was already open
  181. }
  182.  
  183.  
  184. //=================================================================================
  185. // CWithDialogState helper class
  186. //
  187. //    This is a stack-based object that sets up state for a modal dialog in its
  188. //    constructor, and resets the state in the destructor. It deactivates the front
  189. //    window, removes the "Redo" item from the Edit menu, and updates the Mac scrap.
  190. //=================================================================================
  191.  
  192. CWithDialogState::CWithDialogState( Environment *ev, ODSession *session )
  193. {
  194.     fEv = ev;
  195.     fWindowState = session->GetWindowState(ev);
  196.     TempODMenuBar menuBar = fWindowState->AcquireCurrentMenuBar(ev);
  197.     fWindowState->DeactivateFrontWindows(ev);
  198.     ODDialogBegin(ev, session, menuBar, kODNULL);
  199. }
  200.  
  201. CWithDialogState::~CWithDialogState( )
  202. {
  203.     ODDialogEnd();
  204.     fWindowState->ActivateFrontWindows(fEv);
  205. }
  206.  
  207.  
  208. //=================================================================================
  209. // BusyCursor helper function
  210. //=================================================================================
  211.  
  212. void BusyCursor( )
  213. {
  214.     SetCursor(*GetCursor(watchCursor));
  215. }
  216.  
  217. //=================================================================================
  218. // CPrinter implementation
  219. //=================================================================================
  220.  
  221. //---------------------------------------------------------------------------------
  222. // CPrinter::New  [static method]
  223. //---------------------------------------------------------------------------------
  224.  
  225. CPrinter* CPrinter::New( Environment *ev, ODStorageUnit *su )
  226. {
  227.     // Create & initialize the appropriate type of CPrinter object:
  228.     
  229.     long gxVersion, gxPrintVersion;
  230.     CPrinter *p;
  231.  
  232.     if ( Gestalt(gestaltGraphicsVersion, &gxVersion) == noErr &&
  233.             Gestalt(gestaltGXPrintingMgrVersion, &gxPrintVersion) == noErr &&
  234.             (void*)GXInitPrinting != (void*)kUnresolvedCFragSymbolAddress )
  235.         p= new CGXPrinter;
  236.     else
  237.         p= new CQDPrinter;
  238.         
  239.     TRY{
  240.         p->Initialize(ev,su);
  241.     }CATCH_ALL{
  242.         delete p;
  243.         RERAISE;
  244.     }ENDTRY
  245.     return p;
  246. }
  247.  
  248. //---------------------------------------------------------------------------------
  249. // CPrinter::CPrinter
  250. //---------------------------------------------------------------------------------
  251.  
  252. CPrinter::CPrinter()
  253. {
  254.     fDirty = kODFalse;
  255.     fPrintFacet = kODNULL;
  256.     fPrintingOpen = kODFalse;
  257. }
  258.  
  259. //---------------------------------------------------------------------------------
  260. // CPrinter::~CPrinter
  261. //---------------------------------------------------------------------------------
  262.  
  263. CPrinter::~CPrinter()
  264. {
  265.     WASSERTM(!fPrintingOpen,"Printing was not closed");
  266.     WASSERT(fPrintFacet==kODNULL);
  267.     ODSafeReleaseObject(fSU);
  268. }
  269.  
  270. //---------------------------------------------------------------------------------
  271. // CPrinter::Initialize
  272. //---------------------------------------------------------------------------------
  273.  
  274. void CPrinter::Initialize( Environment *ev, ODStorageUnit *su )
  275. {
  276.     ODAcquireObject(ev,su);
  277.     fSU = su;
  278.     fSession = ODGetSession(ev,su);
  279. }
  280.  
  281. //---------------------------------------------------------------------------------
  282. // CPrinter::OpenPrinting
  283. //---------------------------------------------------------------------------------
  284.  
  285. void CPrinter::OpenPrinting()
  286. {
  287.     WASSERTM(!fPrintingOpen,"OpenPrinting called twice");
  288.     fPrintingOpen = kODTrue;
  289. }
  290.  
  291. //---------------------------------------------------------------------------------
  292. // CPrinter::ClosePrinting
  293. //---------------------------------------------------------------------------------
  294.  
  295. void CPrinter::ClosePrinting()
  296. {
  297.     WASSERTM(fPrintingOpen,"ClosePrinting called twice");
  298.     fPrintingOpen = kODFalse;
  299. }
  300.  
  301. //---------------------------------------------------------------------------------
  302. // CPrinter::GetPlatformPrintJob
  303. //---------------------------------------------------------------------------------
  304.  
  305. ODPlatformPrintJob CPrinter::GetPlatformPrintJob( Environment* ev )
  306. {
  307.     // If the print job has not yet been loaded/created, do so now.
  308.     // Try to read a graphics-system-specific value from the standard page-setup property.
  309.     // The platform-specific subclass will do the dirty work of interpreting the
  310.     // data in the value, which we read into a handle for its convenience.
  311.     // If there is no stored page setup or it couldn't be read, make up a new one.
  312.     
  313.     ODPlatformPrintJob job = this->BasicGetPlatformPrintJob( );
  314.     
  315.     if( !job ) {
  316.         CWithPrintingOpen w(this);
  317.         
  318.         TRY
  319.             // Focus the storageUnit to the Print Job property.
  320.             if ( fSU->Exists(ev, kODPropPageSetup, kODNULL, 0) )
  321.             {
  322.                 ODValueType valueType = this->GetValueType();
  323.                 ODBoolean exists = fSU->Exists(ev,kODPropPageSetup,valueType,0);
  324.                 if( !exists ) {
  325.                     // Couldn't find main value type, try secondary one:
  326.                     valueType = this->GetSecondaryValueType();
  327.                     exists = valueType!=kODNULL && fSU->Exists(ev,kODPropPageSetup,valueType,0);
  328.                 }
  329.                 if( exists ) {
  330.                     // Found a value, now read it:
  331.                     fSU->Focus(ev, kODPropPageSetup, 0, valueType, 0, kODPosAll);
  332.                 
  333.                     ODULong size = fSU->GetSize(ev);
  334.                     TempODHandle data = ODNewHandle(size);
  335.                     StorageUnitGetValue(fSU,ev,size,ODLockHandle(data));
  336.                     ODUnlockHandle(data);
  337.                     job= this->ReadJobFromHandle(valueType,data.DontDelete());
  338.                 }
  339.             }
  340.         CATCH_ALL
  341.             WARN("Error %d internalizing print job",ErrorCode());
  342.         ENDTRY
  343.         
  344.         if( !job ) {
  345.             // Let's just make a new one:
  346.             job= this->CreateNewJob();
  347.             ASSERT(job!=kODNULL,kODErrAssertionFailed);
  348.         }
  349.     }
  350.     return job;
  351. }
  352.  
  353. //---------------------------------------------------------------------------------
  354. // CPrinter::Externalize
  355. //---------------------------------------------------------------------------------
  356.  
  357. void CPrinter::Externalize( Environment* ev, ODStorageUnit *su /*=kODNULL*/ )
  358. {
  359.     // su may be different from the part's storage unit (fSU) if the part
  360.     // is being cloned. NULL means use part's storage unit.
  361.     
  362.     if( su==kODNULL ) su=fSU;
  363.     
  364.     if( fDirty || su!=fSU ) {
  365.         TRY
  366.             CWithPrintingOpen w(this);
  367.             this->GetPlatformPrintJob(ev);
  368.             
  369.             TempODHandle data = this->CopyJobToHandle();
  370.             
  371.             // Focus to / create the Print Job property & value:
  372.             ODSUForceFocus(ev,su,kODPropPageSetup, this->GetValueType());
  373.             ODSize size = su->GetSize(ev);
  374.             if( size>0 )
  375.                 su->DeleteValue(ev,size);
  376.             StorageUnitSetValue(su,ev,ODGetHandleSize(data),ODLockHandle(data));
  377.             
  378.             if( su==fSU )
  379.                 fDirty = kODFalse;
  380.         CATCH_ALL
  381.             // Prevent the lack of a selected printer from throwing an error.
  382.             if ( ErrorCode() != fnfErr )
  383.                 RERAISE;
  384.         ENDTRY
  385.     }
  386. }
  387.  
  388. //---------------------------------------------------------------------------------
  389. // CPrinter::PageSetup
  390. //---------------------------------------------------------------------------------
  391.  
  392. ODBoolean CPrinter::PageSetup(Environment* ev)
  393. {
  394.     ODBoolean success = kODFalse;
  395.  
  396.     TRY
  397.         BusyCursor();
  398.         CWithPrintingOpen w(this);
  399.         CWithDialogState d(ev,fSession);
  400.         
  401.         this->GetPlatformPrintJob(ev);
  402.         
  403.         // Display the Page Setup dialog.
  404.         ODError err = kODNoError;
  405.         TRY{
  406.             InitCursor();
  407.             success = this->RunPageSetupDialog(ev);
  408.             if( success )
  409.                 fDirty = kODTrue;
  410.         }CATCH_ALL{
  411.             err = ErrorCode();
  412.         }ENDTRY
  413.         
  414.         THROW_IF_ERROR(err);
  415.  
  416.     CATCH_ALL
  417.         this->DisplayError(ev, ErrorCode());
  418.         success= kODFalse;
  419.     ENDTRY
  420.     InitCursor();
  421.     
  422.     return success;
  423. }
  424.  
  425. //---------------------------------------------------------------------------------
  426. // CPrinter::PrintDocument
  427. //---------------------------------------------------------------------------------
  428.  
  429. void CPrinter::PrintDocument(Environment* ev, ODFrame* initiator, ODShape* area /*=kODNULL*/)
  430. {
  431.     GrafPtr savePort;
  432.     GetPort(&savePort);
  433.     
  434.     BusyCursor();
  435.     
  436.     // If no area is specified, use the frameshape:
  437.     ODBoolean noAreaSupplied = (area==kODNULL);
  438.     if( noAreaSupplied )
  439.         area = initiator->AcquireFrameShape(ev,kODNULL);
  440.  
  441.     TRY
  442.         CWithDialogState d(ev,fSession);
  443.         
  444.         this->GetPlatformPrintJob(ev);
  445.         
  446.         CWithPrintingOpen w(this);
  447.     
  448.         ODError err = kODNoError;
  449.         TRY{
  450.             InitCursor();
  451.             if ( this->RunPrintDialog(ev) ) {
  452.                 BusyCursor();
  453.                 // Create OpenDoc printing geometry objects.
  454.                 this->SetupPrintingEnv(ev, initiator, area);
  455.             
  456.                 this->DoPrint(ev,area);
  457.             }
  458.         }CATCH_ALL{
  459.             err = ErrorCode();
  460.         }ENDTRY
  461.         
  462.         // Tear down printing objects. We do this here instead of right after DoPrint
  463.         // so that the cleanup will happen even if SetupPrintingEnv or DoPrint throw.
  464.         this->CleanupPrintingEnv(ev, initiator);
  465.  
  466.         THROW_IF_ERROR(err);        // Reraise the error, if any
  467.     
  468.     CATCH_ALL
  469.         // error occurred dialog
  470.         this->DisplayError(ev, ErrorCode());
  471.         if( noAreaSupplied )
  472.             ODReleaseObject(ev,area);
  473.     ENDTRY
  474.     
  475.     SetPort(savePort);
  476. }
  477.  
  478. //---------------------------------------------------------------------------------
  479. // CPrinter::SetupPrintingEnv
  480. //---------------------------------------------------------------------------------
  481.  
  482. void CPrinter::SetupPrintingEnv(Environment* ev, ODFrame* initiator, ODShape *area)
  483. {
  484.     if( fPrintFacet )
  485.         return;
  486.         
  487.     TempODPart part = initiator->AcquirePart(ev);
  488.  
  489.     // Create an external transform for our new facet
  490.     TempODTransform xtransform = initiator->CreateTransform(ev);
  491.     
  492.     // Create an OpenDoc shape equal to one page
  493.     ODRect cliprect = this->GetPageRect(ev);
  494.  
  495.     TempODShape clipshape = initiator->CreateShape(ev);
  496.     clipshape->SetRectangle(ev, &cliprect);
  497.  
  498.     // Get info about the type of canvas to create.
  499.     ODGraphicsSystem arch = this->GetGraphicsSystem();
  500.     ODPlatformCanvas port = this->CreatePrintingPlatformCanvas(ev,arch,initiator,area);
  501.  
  502.     // Get the window state to create objects. We need to do this
  503.     // because we don't have a valid facet yet.
  504.     ODWindowState* windowState = fSession->GetWindowState(ev);
  505.     
  506.     // Creating a printing canvas to add to our new facet.
  507.     ODCanvas* canvas = windowState->CreateCanvas(ev, arch, port, kODFalse, kODFalse);
  508.     TempODObject tempcanvas = canvas;        // Make sure it gets deleted on exception
  509.     if( arch != kODQuickDraw ) {
  510.         // Set up QD platform canvas if there isn't one already:
  511.         canvas->SetPlatformCanvas(ev, kODQuickDraw,
  512.                         this->CreatePrintingPlatformCanvas(ev,kODQuickDraw,initiator,area));
  513.     }
  514.     
  515.     canvas->SetOwner(ev, part);
  516.     canvas->SetPlatformPrintJob(ev, arch, this->GetPlatformPrintJob(ev));
  517.     
  518.     // Create a printing facet.
  519.     tempcanvas=kODNULL;
  520.     fPrintFacet = windowState->CreateFacet(ev, initiator, clipshape, xtransform,
  521.                                                 canvas, kODNULL);
  522.     
  523.     // Notify the intiator that a printing facet has been added to it.
  524.     TRY{
  525.         initiator->FacetAdded(ev, fPrintFacet);
  526.     }CATCH_ALL{
  527.         // ignore exceptions from part.
  528.     }ENDTRY
  529. }
  530.  
  531. //---------------------------------------------------------------------------------
  532. // CPrinter::CleanupPrintingEnv
  533. //---------------------------------------------------------------------------------
  534.  
  535. void CPrinter::CleanupPrintingEnv(Environment* ev, ODFrame* initiator)
  536. {
  537.     // Subclass should override to dispose platform canvas / platform print-job.
  538.     
  539.     if( fPrintFacet ) {
  540.         TRY{
  541.             initiator->FacetRemoved(ev, fPrintFacet);
  542.         }CATCH_ALL{
  543.         }ENDTRY
  544.         ODCanvas *canvas = fPrintFacet->GetCanvas(ev);
  545.         canvas->SetFacet(ev,kODNULL);
  546.         ODDeleteObject(fPrintFacet);
  547.         ODDeleteObject(canvas);
  548.     }
  549. }
  550.  
  551. //---------------------------------------------------------------------------------
  552. // CPrinter::CountPages
  553. //---------------------------------------------------------------------------------
  554.  
  555. ODULong CPrinter::CountPages(Environment* ev, ODShape* area)
  556. {
  557.     ODRect contentRect;
  558.     area->GetBoundingBox(ev, &contentRect);
  559.     
  560.     ODRect pageRect = this->GetPageRect(ev);
  561.     
  562.     ODULong horiPages = (contentRect.Width()+pageRect.Width()-1)   / pageRect.Width();
  563.     ODULong vertPages = (contentRect.Height()+pageRect.Height()-1) / pageRect.Height();
  564.     
  565.     ODULong pageCount = horiPages * vertPages;
  566.     if( pageCount == 0 )
  567.         pageCount = 1;
  568.     
  569.     return pageCount;
  570. }
  571.  
  572. //---------------------------------------------------------------------------------
  573. // CPrinter::SetPage
  574. //---------------------------------------------------------------------------------
  575.  
  576. void CPrinter::SetPage(Environment* ev, ODUShort pageNum, ODShape* area)
  577. {
  578.     ODRect contentRect;
  579.     area->GetBoundingBox(ev, &contentRect);
  580.     
  581.     ODRect pageRect = this->GetPageRect(ev);
  582.     
  583.     // Calc horizontal pages, don't let be less than one
  584.     ODUShort horiPages = (contentRect.Width()+pageRect.Width()-1) / pageRect.Width();
  585.     if (horiPages < 1)
  586.         horiPages = 1;
  587.     
  588.     // Create a transform which translates the clip shape (page region)
  589.     // back to a {0,0} coordinate space.
  590.     ODPoint offset;
  591.     offset.x = -( contentRect.left + ((pageNum - 1) % horiPages) * pageRect.Width() );
  592.     offset.y = -( contentRect.top  + ((pageNum - 1) / horiPages) * pageRect.Height() ); 
  593.     
  594.     TempODTransform transform = fPrintFacet->CreateTransform(ev);
  595.     transform->SetOffset(ev, &offset);
  596.     
  597.     // Set up a clip-shape to fit the transformed facet:
  598.     TempODShape clipShape = fPrintFacet->CreateShape(ev);
  599.     clipShape->SetRectangle(ev, &pageRect);
  600.     clipShape->InverseTransform(ev,transform);
  601.     clipShape->Intersect(ev,area);                    // Restrict to frameshape
  602.  
  603.     // Update the facet's geometry.
  604.     fPrintFacet->ChangeGeometry(ev, clipShape, transform, fPrintFacet->GetCanvas(ev));
  605. }
  606.  
  607. //---------------------------------------------------------------------------------
  608. // CPrinter::PrintPage
  609. //---------------------------------------------------------------------------------
  610.  
  611. void CPrinter::PrintPage(Environment* ev, ODUShort page, ODShape *area)
  612. {
  613.     // Main routine to print a particular page.
  614.     
  615.     this->SetPage(ev, page, area);
  616.     this->OpenPage(ev, page);
  617.     
  618.     TempODShape clip = fPrintFacet->AcquireClipShape(ev, kODNULL);
  619.     fPrintFacet->Update(ev, clip, kODNULL);
  620.     
  621.     this->ClosePage(ev);
  622. }
  623.  
  624. //---------------------------------------------------------------------------------
  625. // CPrinter::DisplayError
  626. //---------------------------------------------------------------------------------
  627.  
  628. void CPrinter::DisplayError(Environment* ev, ODSShort error)
  629. {
  630.     Str255        message;
  631.     Str15        number;
  632.     
  633.     CUsingLibraryResources r;
  634.     CWithDialogState d(ev,fSession);
  635.     
  636.     // Use the default (generic) error message unless we recognize the
  637.     // error number.
  638.     ODUShort index = 1;
  639.     if ( error == fnfErr ) index = 2;        // no printer selected.
  640.     
  641.     GetIndString(message, rPrintErrorsID, index);
  642.     NumToString(error,number);
  643.     ParamText(message,number,kODNULL,kODNULL);
  644.  
  645.     ShowAlert(ev,rPrintErrorDialog,kODNULL,fSession);
  646. }
  647.